﻿Imports System.ComponentModel

''' <summary>
''' 
''' </summary>
''' <remarks></remarks>
Public Class Model

    Private Shared _instance As Model

    ''' <summary>
    ''' 
    ''' </summary>
    ''' <remarks></remarks>
    Public Shared ReadOnly Property Instance As Model
        Get
            If _instance Is Nothing Then
                _instance = New Model()
            End If
            Return _instance
        End Get
    End Property

    ''' <summary>
    ''' 
    ''' </summary>
    ''' <remarks></remarks>
    Friend Sub UpdateAll()
        For Each k In Indicators
            If Not k.Equals(IndicatorKey.None) Then
                GetIndicator(k).Calculate()
            End If
        Next
        RaiseEvent Resfreshed(Me, EventArgs.Empty)
    End Sub

    Private _indicators As New Dictionary(Of IndicatorKey, Indicator)
    ''' <summary>
    ''' 
    ''' </summary>
    ''' <remarks></remarks>
    Sub New()
        _indicators.Add(IndicatorKey.None, Nothing)
        _indicators.Add("Random", New RandomIndicator())
        _indicators.Add("Aggregate", New AggregateIndicator())
    End Sub

    ''' <summary>
    ''' 
    ''' </summary>
    ''' <remarks></remarks>
    Public ReadOnly Property Indicators As IEnumerable(Of IndicatorKey)
        Get
            Return _indicators.Keys
        End Get
    End Property
    ''' <summary>
    ''' 
    ''' </summary>
    ''' <remarks></remarks>
    Public Function GetIndicator(ByVal name As String) As Indicator
        Return _indicators(name)
    End Function
    ''' <summary>
    ''' 
    ''' </summary>
    ''' <remarks></remarks>
    Public Function GetIndicator(ByVal key As IndicatorKey) As Indicator
        Return _indicators(key)
    End Function




    Public Event Resfreshed As EventHandler
End Class

''' <summary>
''' 
''' </summary>
''' <remarks></remarks>
Public Class IndicatorKey
    Friend name As String
    Private isnone As Boolean = False

    ''' <summary>
    ''' 
    ''' </summary>
    ''' <remarks></remarks>
    Public Shared ReadOnly Property None As IndicatorKey
        Get
            Return New IndicatorKey() With {.isnone = True}
        End Get
    End Property
    ''' <summary>
    ''' 
    ''' </summary>
    ''' <remarks></remarks>
    Public Shared Widening Operator CType(ByVal name As String) As IndicatorKey
        If String.IsNullOrWhiteSpace(name) Or String.IsNullOrEmpty(name) Then
            Return None
        End If
        Return New IndicatorKey() With {.name = name}
    End Operator

    ''' <summary>
    ''' 
    ''' </summary>
    ''' <remarks></remarks>
    Public Overrides Function GetHashCode() As Integer
        If Me.isnone Then
            Return 0
        End If
        Return name.GetHashCode()
    End Function

    ''' <summary>
    ''' 
    ''' </summary>
    ''' <remarks></remarks>
    Public Overrides Function Equals(ByVal obj As Object) As Boolean
        Dim objk = TryCast(obj, IndicatorKey)
        If objk Is Nothing Then Return False
        If Me.isnone And objk.isnone Then Return True
        If Not Me.isnone And Not objk.isnone Then
            Return name.Equals(objk.name)
        End If
        Return False
    End Function

    ''' <summary>
    ''' 
    ''' </summary>
    ''' <remarks></remarks>
    Public Overrides Function ToString() As String
        Return If(Me.isnone, "(None)", name)
    End Function
End Class

''' <summary>
''' 
''' </summary>
''' <remarks></remarks>
Public Class Indicator
    Implements INotifyPropertyChanged

    ''' <summary>
    ''' 
    ''' </summary>
    ''' <remarks></remarks>
    Public Overridable Sub Calculate()
        Throw New NotImplementedException()
    End Sub

    ''' <summary>
    ''' 
    ''' </summary>
    ''' <remarks></remarks>
    Public Property UseDimension As Boolean

    ''' <summary>
    ''' 
    ''' </summary>
    ''' <remarks></remarks>
    Public Property Dimension As String

    ''' <summary>
    ''' 
    ''' </summary>
    ''' <remarks></remarks>
    Protected Sub OnPropertyChanged(ByVal prop As String)
        RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(prop))
    End Sub

    Private Event PropertyChanged(ByVal sender As Object, ByVal e As System.ComponentModel.PropertyChangedEventArgs) Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged
End Class

''' <summary>
''' 
''' </summary>
''' <remarks></remarks>
Public Class RandomIndicator
    Inherits NumberIndicator

    Private Shared rnd As New Random(Now.Millisecond)

    Private _value As Double
    ''' <summary>
    ''' 
    ''' </summary>
    ''' <remarks></remarks>
    Public Overrides Sub Calculate()
        _value = rnd.Next(1, 10)
        OnPropertyChanged("Value")
    End Sub
    ''' <summary>
    ''' 
    ''' </summary>
    ''' <remarks></remarks>
    Public Overrides ReadOnly Property Value As Double
        Get
            Return _value
        End Get
    End Property
End Class

''' <summary>
''' 
''' </summary>
''' <remarks></remarks>
Public Class TypedIndicator(Of T)
    Inherits Indicator

    ''' <summary>
    ''' 
    ''' </summary>
    ''' <remarks></remarks>
    Public Overridable ReadOnly Property Value As T
        Get
            Throw New NotImplementedException()
        End Get
    End Property
End Class

''' <summary>
''' 
''' </summary>
''' <remarks></remarks>
Public Class NumberIndicator
    Inherits TypedIndicator(Of Double)


End Class

''' <summary>
''' 
''' </summary>
''' <remarks></remarks>
Public Class SerieIndicator
    Inherits TypedIndicator(Of IEnumerable(Of Double))


End Class

''' <summary>
''' 
''' </summary>
''' <remarks></remarks>
Public Class AggregateIndicator
    Inherits NumberIndicator

    ''' <summary>
    ''' 
    ''' </summary>
    ''' <remarks></remarks>
    Public Property Method As AggregateMethod

    ''' <summary>
    ''' 
    ''' </summary>
    ''' <remarks></remarks>
    Public Property MethodParam As Object

    ''' <summary>
    ''' 
    ''' </summary>
    ''' <remarks></remarks>
    Public Property Variable As String

    ''' <summary>
    ''' 
    ''' </summary>
    ''' <remarks></remarks>
    Public Overrides Sub Calculate()
        Return
        Select Case Method
            Case AggregateMethod.Count
                _value = TestData.DataIndicator.Count()

            Case AggregateMethod.Sum
                _value = Aggregate e In TestData.DataIndicator Into Sum(CDbl(e(Variable)))

            Case AggregateMethod.Avg
                _value = Aggregate e In TestData.DataIndicator Into Average(CDbl(e(Variable)))

            Case AggregateMethod.Max
                _value = Aggregate e In TestData.DataIndicator Into Max(CDbl(e(Variable)))

            Case AggregateMethod.Min
                _value = Aggregate e In TestData.DataIndicator Into Min(CDbl(e(Variable)))

            Case AggregateMethod.EqType
                Dim c = TestData.DataIndicator.Count()
                Dim m = Aggregate e In TestData.DataIndicator Into Average(CDbl(e(Variable)))

                '_value =Math.Sqrt( _
                '    (Aggregate e In TestData.DataIndicator Into sum(Math.Pow(CDbl(e(Variable))-m)

            Case AggregateMethod.Median
                Dim c = TestData.DataIndicator.Count()
                Dim tmp = (From e In TestData.DataIndicator Order By CDbl(e(Variable)) Select e).ToArray()
                If c Mod 2 = 0 Then
                    Dim c1 = tmp(c / 2)(Variable)
                    Dim c2 = tmp((c / 2) - 1)(Variable)
                    _value = (c1 + c2) / 2
                Else
                    _value = tmp((c - 1) / 2)(Variable)
                End If
        End Select
        OnPropertyChanged("Value")
    End Sub

    Private _value As Double
    ''' <summary>
    ''' 
    ''' </summary>
    ''' <remarks></remarks>
    Public Overrides ReadOnly Property Value As Double
        Get
            Return _value
        End Get
    End Property

    Private DynMethod As Func(Of Double)

    ''' <summary>
    ''' 
    ''' </summary>
    ''' <remarks></remarks>
    Public Shared Operator +(ByVal left As AggregateIndicator, ByVal right As AggregateIndicator) As AggregateIndicator
        Dim f = Function() left.DynMethod() + right.DynMethod()
        Return New AggregateIndicator() With {.DynMethod = f}
    End Operator
    ''' <summary>
    ''' 
    ''' </summary>
    ''' <remarks></remarks>
    Public Shared Operator +(ByVal left As Double, ByVal right As AggregateIndicator) As AggregateIndicator
        Dim f = Function() left + right.DynMethod()
        Return New AggregateIndicator() With {.DynMethod = f}
    End Operator
    ''' <summary>
    ''' 
    ''' </summary>
    ''' <remarks></remarks>
    Public Shared Operator +(ByVal left As AggregateIndicator, ByVal right As Double) As AggregateIndicator
        Dim f = Function() left.DynMethod() + right
        Return New AggregateIndicator() With {.DynMethod = f}
    End Operator
    ''' <summary>
    ''' 
    ''' </summary>
    ''' <remarks></remarks>
    Public Shared Operator -(ByVal left As AggregateIndicator, ByVal right As AggregateIndicator) As AggregateIndicator
        Dim f = Function() left.DynMethod() - right.DynMethod()
        Return New AggregateIndicator() With {.DynMethod = f}
    End Operator
    ''' <summary>
    ''' 
    ''' </summary>
    ''' <remarks></remarks>
    Public Shared Operator -(ByVal left As Double, ByVal right As AggregateIndicator) As AggregateIndicator
        Dim f = Function() left - right.DynMethod()
        Return New AggregateIndicator() With {.DynMethod = f}
    End Operator
    ''' <summary>
    ''' 
    ''' </summary>
    ''' <remarks></remarks>
    Public Shared Operator -(ByVal left As AggregateIndicator, ByVal right As Double) As AggregateIndicator
        Dim f = Function() left.DynMethod() - right
        Return New AggregateIndicator() With {.DynMethod = f}
    End Operator
    ''' <summary>
    ''' 
    ''' </summary>
    ''' <remarks></remarks>
    Public Shared Operator *(ByVal left As AggregateIndicator, ByVal right As AggregateIndicator) As AggregateIndicator
        Dim f = Function() left.DynMethod() * right.DynMethod()
        Return New AggregateIndicator() With {.DynMethod = f}
    End Operator
    ''' <summary>
    ''' 
    ''' </summary>
    ''' <remarks></remarks>
    Public Shared Operator *(ByVal left As Double, ByVal right As AggregateIndicator) As AggregateIndicator
        Dim f = Function() left * right.DynMethod()
        Return New AggregateIndicator() With {.DynMethod = f}
    End Operator
    ''' <summary>
    ''' 
    ''' </summary>
    ''' <remarks></remarks>
    Public Shared Operator *(ByVal left As AggregateIndicator, ByVal right As Double) As AggregateIndicator
        Dim f = Function() left.DynMethod() * right
        Return New AggregateIndicator() With {.DynMethod = f}
    End Operator
    ''' <summary>
    ''' 
    ''' </summary>
    ''' <remarks></remarks>
    Public Shared Operator /(ByVal left As AggregateIndicator, ByVal right As AggregateIndicator) As AggregateIndicator
        Dim f = Function() left.DynMethod() / right.DynMethod()
        Return New AggregateIndicator() With {.DynMethod = f}
    End Operator
    ''' <summary>
    ''' 
    ''' </summary>
    ''' <remarks></remarks>
    Public Shared Operator /(ByVal left As Double, ByVal right As AggregateIndicator) As AggregateIndicator
        Dim f = Function() left / right.DynMethod()
        Return New AggregateIndicator() With {.DynMethod = f}
    End Operator
    ''' <summary>
    ''' 
    ''' </summary>
    ''' <remarks></remarks>
    Public Shared Operator /(ByVal left As AggregateIndicator, ByVal right As Double) As AggregateIndicator
        Dim f = Function() left.DynMethod() / right
        Return New AggregateIndicator() With {.DynMethod = f}
    End Operator
    ''' <summary>
    ''' 
    ''' </summary>
    ''' <remarks></remarks>
    Public Shared Function Log(ByVal indic As AggregateIndicator, Optional ByVal base As Double = Math.E) As AggregateIndicator
        Dim f = Function() Math.Log(indic.DynMethod(), base)
        Return New AggregateIndicator() With {.DynMethod = f}
    End Function
    ''' <summary>
    ''' 
    ''' </summary>
    ''' <remarks></remarks>
    Public Shared Function Exp(ByVal indic As AggregateIndicator) As AggregateIndicator
        Dim f = Function() Math.Exp(indic.DynMethod())
        Return New AggregateIndicator() With {.DynMethod = f}
    End Function
    ''' <summary>
    ''' 
    ''' </summary>
    ''' <remarks></remarks>
    Public Shared Function Pow(ByVal indic As AggregateIndicator, Optional ByVal base As Double = Math.E) As AggregateIndicator
        Dim f = Function() Math.Pow(indic.DynMethod(), base)
        Return New AggregateIndicator() With {.DynMethod = f}
    End Function



End Class

''' <summary>
''' Méthode de calcul d'indicateur aggrégé
''' </summary>
''' <remarks>
''' 
''' </remarks>
Public Enum AggregateMethod
    ''' <summary>
    ''' Compte
    ''' </summary>
    ''' <remarks>
    ''' 
    ''' </remarks>
    Count
    ''' <summary>
    ''' Somme
    ''' </summary>
    ''' <remarks>
    ''' 
    ''' </remarks>
    Sum
    ''' <summary>
    ''' Moyenne
    ''' </summary>
    ''' <remarks>
    ''' 
    ''' </remarks>
    Avg
    ''' <summary>
    ''' Maximum
    ''' </summary>
    ''' <remarks>
    ''' 
    ''' </remarks>
    Max
    ''' <summary>
    ''' Minimum
    ''' </summary>
    ''' <remarks>
    ''' 
    ''' </remarks>
    Min
    ''' <summary>
    ''' Médiane
    ''' </summary>
    ''' <remarks>
    ''' 
    ''' </remarks>
    Median
    ''' <summary>
    ''' Centile( nécessite un parametre supplémentaire )
    ''' </summary>
    ''' <remarks>
    ''' 
    ''' </remarks>
    Centile
    ''' <summary>
    ''' Ecart-Type
    ''' </summary>
    ''' <remarks>
    ''' 
    ''' </remarks>
    EqType
End Enum
